#!/usr/bin/env jruby
# -*- coding: us-ascii -*-

require 'test/unit'
dir = File.dirname(__FILE__)
require File.join(dir, '..', '..', 'lib', 'auxil', 'simplehash')

########################################

module Constants4SimpleHashTests
  ISMALL = 1
  IMEDIUM = 20
  APLUS4 = ('a'..'z').to_a + 'eliz'.split('')
  APLUS4SIZE = APLUS4.size
end

module Functions4SimpleHashTests
  include Constants4SimpleHashTests
  
  def add_many_letters(sh)
    APLUS4.each do |letter|
      sh.add(letter, letter)
    end
  end
  
  def get_bucket_item_total(sh)
    sh.inject(0) { |sum, buck| sum += buck.size }
  end
  
  def rletter
    APLUS4[rand(APLUS4SIZE)]
  end
end

########################################

class TestSimpleHashConstructor < Test::Unit::TestCase
  include Constants4SimpleHashTests
  include Functions4SimpleHashTests
  
  def test_should_accept_positive_integer
    assert_nothing_raised { SimpleHash.new(IMEDIUM) }
  end
  
  def test_should_reject_noninteger
    assert_raise(TypeError) { SimpleHash.new(20.0) }
  end
  
  def test_should_reject_nonpositive
    assert_raise(RangeError, 'neg') { SimpleHash.new(-IMEDIUM) }
    assert_raise(RangeError, 'zero') { SimpleHash.new(0) }
  end
  
  def testShouldCreateCorrectNumberOfEmptyBuckets
    sh = SimpleHash.new(IMEDIUM)
    assert_equal IMEDIUM, sh.m
    assert_equal 0, sh.n, 'n'
    assert_equal 0, sh.alpha, 'alpha'
    assert sh.n == get_bucket_item_total(sh)
  end
end

########################################

class TestSimpleHashInvariants < Test::Unit::TestCase
  include Constants4SimpleHashTests
  include Functions4SimpleHashTests
  
  def test_small_should_have_constant_number_of_buckets
    sh = SimpleHash.new(ISMALL)
    mstart = sh.m
    add_many_letters(sh)
    assert_equal mstart, sh.m
  end
  
  def test_medium_should_have_constant_number_of_buckets
    sh = SimpleHash.new(IMEDIUM)
    mstart = sh.m
    add_many_letters(sh)
    assert_equal mstart, sh.m
  end
end

########################################

class TestSimpleHashItems < Test::Unit::TestCase
  include Constants4SimpleHashTests
  include Functions4SimpleHashTests
  
  def setup
    @small = SimpleHash.new(ISMALL)
    @medium = SimpleHash.new(IMEDIUM)
  end
  
  def test_small_should_contain_1_item
    letter = rletter
    @small.add(letter, letter)
    assert_equal 1, @small.n
  end
  
  def test_medium_should_contain_1_item
    letter = rletter
    @medium.add(letter, letter)
    assert_equal 1, @medium.n
  end
  
  def test_small_should_contain_many_items
    add_many_letters(@small)
    assert_equal APLUS4SIZE, @small.n
  end
  
  def test_medium_should_contain_many_items
    add_many_letters(@medium)
    assert_equal APLUS4SIZE, @medium.n
  end
  
  <<-foo
  [[], ["d", "r", "z", "z"], ["f", "h"], [], ["k", "m", "n", "v"], [], 
  ["c", "l", "l"], ["g", "o"], [], [], ["a", "i", "i"], [], ["e", "e"], 
  ["j"], ["t"], ["p", "w"], [], ["s", "x"], ["u"], ["b", "q", "y"]]
  foo
  
  def test_alphabet_groups
    add_many_letters(@medium)
    all = @medium.to_a
    
    APLUS4[-4,4].each do |char|  # 'eliz'
      ee = all.select { |a| a.include? char }
      assert_equal 1, ee.size, char  # both e's in one group
      assert_equal 2, ee.flatten.select { |x| x.include? char }.size, char
      all -= ee
    end
  end
end
